/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
 */

package com.xjw.service;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.xjw.controller.ChessController;
import com.xjw.entity.*;
import com.xjw.mapper.ChessMapper;
import com.xjw.tool.ArrayUtil;
import com.xjw.tool.ChessUtil;
import com.xjw.tool.DgUtil;
import com.xjw.tool.MybatisUtils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import javafx.event.EventHandler;
import javafx.scene.control.Alert;
import javafx.scene.input.MouseEvent;

import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.io.Resources;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Random;

public class PlayAction implements EventHandler<MouseEvent> {

    public static int[][] map = new int[15][15];

    /**
     * fiveChess表示五子棋游戏模型
     */
    private final FiveChess fiveChess;

    /**
     * chessPane表示五子棋显示面板
     */
    private final ChessController chessPane;

    /**
     * 最后落子
     */
    private static ChessPoint currentPoint;

    /**
     * 游戏结束标识
     */
    private static boolean endFlag = false;

    private static final Log LOG = LogFactory.get("play action:");

    public PlayAction(FiveChess fiveChess, ChessController chessPane) {
        this.chessPane = chessPane;
        this.fiveChess = fiveChess;
    }

    @Override
    public void handle(MouseEvent event) {
        if(chessPane.modelEle.getSelectionModel().getSelectedItem().equals(ChessType.PTOR.getMsg())) {
            ChessPoint point = actionPlay(event);
            ChessPoint chessPoint = DgUtil.dgPoint(point.getPointX(), point.getPointY(),
                    fiveChess.getCurrentSide() == 'W'?'B':'W',fiveChess);
            LOG.info("ai落子:"+chessPoint);
            play(chessPoint.getPointX(),chessPoint.getPointY());
        } else if (chessPane.modelEle.getSelectionModel()
                .getSelectedItem().equals(ChessType.RTOR.getMsg()) ) {
            ThreadUtil.execAsync(()->{
                while (!endFlag) {
                    // 开局第一手
                    if (currentPoint == null) {
                        currentPoint = new ChessPoint(8, 8);
                    }
                    currentPoint = DgUtil.dgPoint(currentPoint.getPointX(), currentPoint.getPointY(),
                            fiveChess.getCurrentSide() == 'W'?'B':'W',fiveChess);
                    LOG.info("ai落子:"+ currentPoint);
                    play(currentPoint.getPointX(), currentPoint.getPointY());
                    ThreadUtil.sleep(1000);
                }
            });
        } else {
            actionPlay(event);
        }
    }

    /**
     * 玩家落子
     *
     * @param event 鼠标事件
     * @return 落子坐标
     */
    private ChessPoint actionPlay(MouseEvent event) {
        //处理鼠标点击事件
        double cell = fiveChess.getCellLen();
        //event.getX()获取鼠标点击x坐标，返回double类型
        double x = event.getX();
        double y = event.getY();

        int i = (int) ((x - 100 + cell / 2) / cell);
        int j = (int) ((y - 100 + cell / 2) / cell);
        play(i,j);
        return new ChessPoint(i, j);
    }

    /**
     * 算法逻辑从威胁点中随出一个，没有危险点就在落子旁边随便放一个
     * @param row 落子x
     * @param col 落子y
     * @param chessColor 落子的颜色
     * @param fiveChess 棋盘
     * @return 算法落子
     */
    private static ChessPoint randomPoint(int row, int col, char chessColor, FiveChess fiveChess){
        ChessAi chessAi = new ChessAi(row, col, chessColor, fiveChess);
        List<ChessPoint> chessPoints = DgUtil.getAllDangerous(chessAi);
        System.out.println(chessColor+"方落子位置："+row+":"+col);
        System.out.println("具有威胁的位置："+chessPoints);
        if(chessPoints.size() > 0) {
            Random rd = new Random();
            return chessPoints.get(rd.nextInt(chessPoints.size()));
        }
        chessPoints.addAll(ChessUtil.getAroundChess(row, col, fiveChess));
        Random rd = new Random();
        return chessPoints.get(rd.nextInt(chessPoints.size()));
    }

    private void play(int i, int j) {
        saveChess(i, j);
        fiveChess.play(i, j);
        chessPane.drawChess(fiveChess.getCellLen());
        endFlag = !fiveChess.judgeGame(i, j, fiveChess.getCurrentSide() == 'B' ? 'W' : 'B');
        if (endFlag) {
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setTitle("五子棋游戏");
            alert.setHeaderText("提示信息");
            alert.setContentText((fiveChess.getCurrentSide() == 'B' ? "白" : "黑") + "方取得胜利！");
            alert.showAndWait();
        }
    }

    public void initPane(){
        fiveChess.setChess(new char[(int) fiveChess.getHeight()][(int) fiveChess.getWidth()]);
        chessPane.drawPane(fiveChess.getCellLen());
        map = new int[15][15];
        for (int i = 0; i < fiveChess.getHeight(); i++) {
            for (int j = 0; j < fiveChess.getWidth(); j++) {
                fiveChess.getChess()[i][j] = ' ';
            }
        }
        DgUtil.chessPoints.clear();
        DgUtil.chessPointList.clear();
    }

    public ChessGame createGame(){
        try{
            ChessGame chessGame = new ChessGame();
            chessGame.setStartTime(DateUtil.now());
            ChessMapper chessMapper = MybatisUtils.getMapper(ChessMapper.class);
            chessMapper.inserGame(chessGame);
            chessPane.goBangIdEle.setText(String.valueOf(chessGame.getTaskId()));
            return chessGame;
        } catch (PersistenceException ex) {
            try {
                InputStream resourceFile = Resources.getResourceAsStream("init.sql");
                String sql = IoUtil.readUtf8(resourceFile);
                String [] sqls = sql.split(";");
                ChessMapper sqlMapper = MybatisUtils.getMapper(ChessMapper.class);
                for(String content:sqls){
                    try{
                        sqlMapper.customQueryItem(content);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            ChessGame chessGame = new ChessGame();
            chessGame.setStartTime(DateUtil.now());
            ChessMapper chessMapper = MybatisUtils.getMapper(ChessMapper.class);
            chessMapper.inserGame(chessGame);
            return chessGame;
        }
    }

    private void saveChess(int i, int j) {
        ChessGameInfo chessGameInfo = new ChessGameInfo();
        map[i-1][j-1] = fiveChess.getCurrentSide() == 'B' ? 1 : 2;
        chessGameInfo.setMap(ArrayUtil.toString(map));
        chessGameInfo.setChessX(i);
        chessGameInfo.setChessY(j);
        chessGameInfo.setTaskId(chessPane.chessGame.getTaskId());
        ChessMapper chessMapper = MybatisUtils.getMapper(ChessMapper.class);
        chessMapper.insertChess(chessGameInfo);
    }

}